from ConfigParser import NoOptionError
from ats.conf import settings 
from ats.log import logger
from ats.sesh import sessionmanager
from mod_python import apache
import types

# -----------------------------------------------------------------------------
# Globals
# -----------------------------------------------------------------------------
urlmap = settings.get_urlmap_conf()
conf = settings.get_config()
log = logger.get_logger()
DEBUG = int(conf.get('settings', 'debug'))
imported = {} # local cache of imported handlers

# -----------------------------------------------------------------------------
# Dispatch function
# -----------------------------------------------------------------------------
def handler(req):
	""" retrieve a handler function object from a 
		full dotted-package name.
		if you gotta time someting...
			import time
			#t1 = time.time()
			something()
			#t2 = time.time()
			#log.error("session time: %f" % (t2 - t1))
	"""
	global DEBUG, imported

	worker = None
	sesh = None
	urlkey = ""
	resource = "/"

	try: # grab session + handler
		url_li = req.uri.strip().split('/')
		if url_li and len(url_li) > 1:
			resource +=  url_li[1]
		urlkey = req.hostname+resource
		sesh = sessionmanager.get_session(req)
		if imported.has_key(urlkey) and imported[urlkey]:
			worker = imported[urlkey]
		else:
			worker = _get_handler(urlmap.get(req.hostname, resource))
			imported[urlkey] = worker
	except (NoOptionError, GetHandlerError), e:
		_urlval = "" 
		if imported.has_key(urlkey):
			_urlval = imported[urlkey]
		log.error("could not map: %s: Error: %s, urlkey=%s, urlval=%s" % \
				(req.uri, e, urlkey, str(_urlval)))
		if DEBUG: raise "Could not map handler"
		return apache.HTTP_NOT_FOUND

	try: # call handler and return response
		code, content, response = _unpack(worker(req, sesh))
		if code == apache.OK:
			req.content_type = content 
			req.headers_out['Pragma'] = "no-cache" 
			req.headers_out['Cache-Control'] = "no-cache" 
			req.headers_out['Expires'] = "-1" 
			req.send_http_header()
			req.write(str(response))
			return code
		elif code == apache.HTTP_SEE_OTHER:
			req.headers_out['Location'] = response 
			req.status = code 
			raise apache.SERVER_RETURN, code 
		else:
			return code
	finally:
		sessionmanager.persist_session(sesh)

# -----------------------------------------------------------------------------
# Helpers
# -----------------------------------------------------------------------------
def _unpack(resp):
	code = apache.OK; content = "text/html"; response = ""
	if not resp:
		raise "Invalid response!"
	if type(resp) is not types.TupleType: 
		response = str(resp)
	elif len(resp) == 3:
		code, content, response = resp
	elif len(resp) == 2:
		code, response = resp
	elif len(resp) == 1:
		response = str(resp[0]) 
	else:
		raise "What the fuk are you trying to return"
	return code, content, response

# -----------------------------------------------------------------------------
def _get_handler(path):
	""" retrieve a handler function object from a 
		full dotted-package name.
	"""
	if not path:
		return None
	pathlist = path.split(".")
	plen = len(pathlist)
	hdlr = __import__(".".join(pathlist[:plen-1]))
	for comp in pathlist[1:]:
		hdlr = getattr(hdlr, comp)
	if not callable(hdlr): 
		raise GetHandlerError("%s is not callable." % path)
	return hdlr 

# -----------------------------------------------------------------------------
# Exceptions
# -----------------------------------------------------------------------------
class GetHandlerError(Exception):
	""" Custom error for the _get_handler method
	"""
	def __init__(self, value):
		self.value = value
		
	def __str__(self):
		return self.value
